f9f0f4a778da0a3ab9e910d65a1acfa64290daca
[openwrt/openwrt.git] /
1 From 88f170814fea74911ceab798a43cbd7c5599bed4 Mon Sep 17 00:00:00 2001
2 From: Marios Makassikis <mmakassikis@freebox.fr>
3 Date: Wed, 15 Oct 2025 09:25:46 +0200
4 Subject: [PATCH] ksmbd: fix recursive locking in RPC handle list access
5
6 Since commit 305853cce3794 ("ksmbd: Fix race condition in RPC handle list
7 access"), ksmbd_session_rpc_method() attempts to lock sess->rpc_lock.
8
9 This causes hung connections / tasks when a client attempts to open
10 a named pipe. Using Samba's rpcclient tool:
11
12 $ rpcclient //192.168.1.254 -U user%password
13 $ rpcclient $> srvinfo
14 <connection hung here>
15
16 Kernel side:
17 "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
18 task:kworker/0:0 state:D stack:0 pid:5021 tgid:5021 ppid:2 flags:0x00200000
19 Workqueue: ksmbd-io handle_ksmbd_work
20 Call trace:
21 __schedule from schedule+0x3c/0x58
22 schedule from schedule_preempt_disabled+0xc/0x10
23 schedule_preempt_disabled from rwsem_down_read_slowpath+0x1b0/0x1d8
24 rwsem_down_read_slowpath from down_read+0x28/0x30
25 down_read from ksmbd_session_rpc_method+0x18/0x3c
26 ksmbd_session_rpc_method from ksmbd_rpc_open+0x34/0x68
27 ksmbd_rpc_open from ksmbd_session_rpc_open+0x194/0x228
28 ksmbd_session_rpc_open from create_smb2_pipe+0x8c/0x2c8
29 create_smb2_pipe from smb2_open+0x10c/0x27ac
30 smb2_open from handle_ksmbd_work+0x238/0x3dc
31 handle_ksmbd_work from process_scheduled_works+0x160/0x25c
32 process_scheduled_works from worker_thread+0x16c/0x1e8
33 worker_thread from kthread+0xa8/0xb8
34 kthread from ret_from_fork+0x14/0x38
35 Exception stack(0x8529ffb0 to 0x8529fff8)
36
37 The task deadlocks because the lock is already held:
38 ksmbd_session_rpc_open
39 down_write(&sess->rpc_lock)
40 ksmbd_rpc_open
41 ksmbd_session_rpc_method
42 down_read(&sess->rpc_lock) <-- deadlock
43
44 Adjust ksmbd_session_rpc_method() callers to take the lock when necessary.
45
46 Fixes: 305853cce3794 ("ksmbd: Fix race condition in RPC handle list access")
47 Signed-off-by: Marios Makassikis <mmakassikis@freebox.fr>
48 Acked-by: Namjae Jeon <linkinjeon@kernel.org>
49 Signed-off-by: Steve French <stfrench@microsoft.com>
50 ---
51 fs/smb/server/mgmt/user_session.c | 7 ++-----
52 fs/smb/server/smb2pdu.c | 9 ++++++++-
53 fs/smb/server/transport_ipc.c | 12 ++++++++++++
54 3 files changed, 22 insertions(+), 6 deletions(-)
55
56 --- a/fs/smb/server/mgmt/user_session.c
57 +++ b/fs/smb/server/mgmt/user_session.c
58 @@ -147,14 +147,11 @@ void ksmbd_session_rpc_close(struct ksmb
59 int ksmbd_session_rpc_method(struct ksmbd_session *sess, int id)
60 {
61 struct ksmbd_session_rpc *entry;
62 - int method;
63
64 - down_read(&sess->rpc_lock);
65 + lockdep_assert_held(&sess->rpc_lock);
66 entry = xa_load(&sess->rpc_handle_list, id);
67 - method = entry ? entry->method : 0;
68 - up_read(&sess->rpc_lock);
69
70 - return method;
71 + return entry ? entry->method : 0;
72 }
73
74 void ksmbd_session_destroy(struct ksmbd_session *sess)
75 --- a/fs/smb/server/smb2pdu.c
76 +++ b/fs/smb/server/smb2pdu.c
77 @@ -4623,8 +4623,15 @@ static int smb2_get_info_file_pipe(struc
78 * pipe without opening it, checking error condition here
79 */
80 id = req->VolatileFileId;
81 - if (!ksmbd_session_rpc_method(sess, id))
82 +
83 + lockdep_assert_not_held(&sess->rpc_lock);
84 +
85 + down_read(&sess->rpc_lock);
86 + if (!ksmbd_session_rpc_method(sess, id)) {
87 + up_read(&sess->rpc_lock);
88 return -ENOENT;
89 + }
90 + up_read(&sess->rpc_lock);
91
92 ksmbd_debug(SMB, "FileInfoClass %u, FileId 0x%llx\n",
93 req->FileInfoClass, req->VolatileFileId);
94 --- a/fs/smb/server/transport_ipc.c
95 +++ b/fs/smb/server/transport_ipc.c
96 @@ -825,6 +825,9 @@ struct ksmbd_rpc_command *ksmbd_rpc_writ
97 if (!msg)
98 return NULL;
99
100 + lockdep_assert_not_held(&sess->rpc_lock);
101 +
102 + down_read(&sess->rpc_lock);
103 msg->type = KSMBD_EVENT_RPC_REQUEST;
104 req = (struct ksmbd_rpc_command *)msg->payload;
105 req->handle = handle;
106 @@ -833,6 +836,7 @@ struct ksmbd_rpc_command *ksmbd_rpc_writ
107 req->flags |= KSMBD_RPC_WRITE_METHOD;
108 req->payload_sz = payload_sz;
109 memcpy(req->payload, payload, payload_sz);
110 + up_read(&sess->rpc_lock);
111
112 resp = ipc_msg_send_request(msg, req->handle);
113 ipc_msg_free(msg);
114 @@ -849,6 +853,9 @@ struct ksmbd_rpc_command *ksmbd_rpc_read
115 if (!msg)
116 return NULL;
117
118 + lockdep_assert_not_held(&sess->rpc_lock);
119 +
120 + down_read(&sess->rpc_lock);
121 msg->type = KSMBD_EVENT_RPC_REQUEST;
122 req = (struct ksmbd_rpc_command *)msg->payload;
123 req->handle = handle;
124 @@ -856,6 +863,7 @@ struct ksmbd_rpc_command *ksmbd_rpc_read
125 req->flags |= rpc_context_flags(sess);
126 req->flags |= KSMBD_RPC_READ_METHOD;
127 req->payload_sz = 0;
128 + up_read(&sess->rpc_lock);
129
130 resp = ipc_msg_send_request(msg, req->handle);
131 ipc_msg_free(msg);
132 @@ -876,6 +884,9 @@ struct ksmbd_rpc_command *ksmbd_rpc_ioct
133 if (!msg)
134 return NULL;
135
136 + lockdep_assert_not_held(&sess->rpc_lock);
137 +
138 + down_read(&sess->rpc_lock);
139 msg->type = KSMBD_EVENT_RPC_REQUEST;
140 req = (struct ksmbd_rpc_command *)msg->payload;
141 req->handle = handle;
142 @@ -884,6 +895,7 @@ struct ksmbd_rpc_command *ksmbd_rpc_ioct
143 req->flags |= KSMBD_RPC_IOCTL_METHOD;
144 req->payload_sz = payload_sz;
145 memcpy(req->payload, payload, payload_sz);
146 + up_read(&sess->rpc_lock);
147
148 resp = ipc_msg_send_request(msg, req->handle);
149 ipc_msg_free(msg);